var ApiFactory = require('lib/ApiFactory')
  , _ = require('underscore')
  , format = require('lib/util/format')
  , crashNameFormat = require('./crashNameFormat')
  , numeral = require('numeral')
  , china = require('lib/geoJSON/china_geo.json')

// START: modified dataSize() from lib/util/format
var numberic=function(v){
  var med,
      tmp_value,
      out_value = parseFloat(v);
  if (isNaN(out_value)||out_value===0) {
      return '0.00';
  }
  med = 0;
  do{
      med += 2;
      tmp_value = out_value.toFixed(med);
  }while(parseFloat(tmp_value)===0&&med<6);
  out_value = tmp_value
  return out_value.toString().replace(/(\d{1,3})(?=(\d{3})+(?:\.))/g, '$1,');
}

var dataSize=function(v){
  var bits = (v).toString().replace(/\.\d+/,'');
  var units = ['B','KB','MB','GB','TB'];
  var i;
  for(i=units.length-1;i+1;i--){
    if(bits>Math.pow(2,i*10)){
      return numberic(v/Math.pow(2,i*10)) + ' '+units[i]
    }
  }
  return numberic(v) + ' b'
}
// END: modified dataSize() from lib/util/format

var propConfig = module.exports.propConfig = {
  'bDTotal':{
    order:'201',
    label:'白屏时间',
    format:format.numSecond,
    parse:function(p){
      return {
        bDTotal:p.bDTotal
      }
    }
  },
  'active':{
    order:'1',
    label:'活跃设备',
    format:format.integer,
    parse:function(p){
      return {
        active:p.val
      }
    }
  },
  'session_count':{
    order:'1',
    label:'活跃会话数',
    format:format.integer,
    parse:function(p){
      return {
        session_count:p.val
      }
    }
  },
  'total_resp_time':{
    order:'1',
    label:'总响应时间',
    format:format.numSecond,
    parse:function(p){
      return {
        total_resp_time:p.val,
        avg_resp:p.count?p.val/p.count:0,
        thp:p.count/((p.et-p.st)/60000),
        resp_count:p.count
      }
    }
  },
  'avg_resp':{
    order:'2',
    label:'平均响应时间',
    format:format.numSecond2,
    parse:function(p){
      return {
        total_resp_time:p.val,
        avg_resp:p.count?p.val/p.count:0,
        thp:p.count/((p.et-p.st)/60000),
        resp_count:p.count
      }
    }
  },
  // 关键元素中使用(精确到小数点后两位，数据校对)
  'avg_resp2':{
    order:'2',
    label:'平均响应时间',
    format:format.numSecond,
    parse:function(p){
      return {
        total_resp_time:p.val,
        avg_resp:p.count?p.val/p.count:0,
        thp:p.count/((p.et-p.st)/60000),
        resp_count:p.count
      }
    }
  },
  'thp':{
    order:'3',
    label:'吞吐量',
    format:function(v){return format.numberic(v)+'cpm'},
    parse:function(p){
      return {
        total_resp_time:p.val,
        avg_resp:p.count?p.val/p.count:0,
        thp:p.count/((p.et-p.st)/60000),
        resp_count:p.count
      }
    }
  },
  'resp_count':{
    order:'3',
    label:'响应次数',
    format:format.integer,
    parse:function(p){
      return {
        total_resp_time:p.val,
        avg_resp:p.count?p.val/p.count:0,
        thp:p.count/((p.et-p.st)/60000),
        resp_count:p.count
      }
    }
  },
  'alert_crash_rate':{
    order:'2',
    label:'崩溃率',
    format:format.rate,
    parse:function(p){
      return {
        alert_crash_rate:p.crashRate,
        error_count:p.count,
        total_count:p.appUseCount
      }
    }
  },
  'error_rate':{
    order:'2',
    label:'错误率',
    format:format.rate,
    parse:function(p){
      return {
        error_rate:p.count?p.val/p.count:0,
        error_count:p.val,
        total_count:p.count
      }
    }
  },
  'error_count':{
    order:'1',
    label:'错误次数',
    format:format.integer,
    parse:function(p){
      return {
        error_rate:p.count?p.val/p.count:0,
        error_count:p.val,
        total_count:p.count
      }
    }
  },
  'total_count':{
    order:'3',
    label:'总次数',
    format:format.integer,
    parse:function(p){
      return {
        error_rate:p.count?p.val/p.count:0,
        error_count:p.val,
        total_count:p.count
      }
    }
  },
  'total_exec':{
    order:'201',
    label:'总执行时间',
    format:format.numSecond,
    parse:function(p){
      return {
        avg_exec:p.count?p.total/p.count:0,
        exec_count:p.count,
        total_exec:p.total,
        max_exec:p.max,
        min_exec:p.min
      }
    }
  },
  'avg_exec_overview':{
    order:'202',
    label:'平均执行时间',
    format:format.numSecond,
    parse:function(p){
      return {
        avg_exec_overview:p.count?p.total/p.count:0,
        exec_count_overview:p.count,
        total_exec_overview:p.total
      }
    }
  },
  'exec_count_overview':{
    order:'203',
    label:'执行次数',
    format:format.integer,
    parse:function(p){
      return {
        avg_exec_overview:p.count?p.total/p.count:0,
        exec_count_overview:p.count,
        total_exec_overview:p.total
      }
    }
  },
  'total_exec_overview':{
    order:'201',
    label:'总执行时间',
    format:format.numSecond,
    parse:function(p){
      return {
        avg_exec_overview:p.count?p.total/p.count:0,
        exec_count_overview:p.count,
        total_exec_overview:p.total
      }
    }
  },
  'avg_exec':{
    order:'202',
    label:'平均执行时间',
    format:format.numSecond,
    parse:function(p){
      return {
        avg_exec:p.count?p.total/p.count:0,
        exec_count:p.count,
        total_exec:p.total,
        max_exec:p.max,
        min_exec:p.min
      }
    }
  },
  'alert_avg_resp':{
    order:'2',
    label:'平均响应时间',
    format:format.numSecond,
    parse:function(p){
      return {
        alert_avg_resp:p.val?p.count/p.val:0,
        exec_count:p.val,
        total_exec:p.count
      }
    }
  },
  'exec_count':{
    order:'203',
    label:'执行次数',
    format:format.integer,
    parse:function(p){
      return {
        avg_exec:p.count?p.total/p.count:0,
        exec_count:p.count,
        total_exec:p.total,
        max_exec:p.max,
        min_exec:p.min
      }
    }
  },
  'max_exec':{
    label:'最大执行时间',
    format:format.numSecond,
    parse:function(p){
      return {
        avg_exec:p.count?p.total/p.count:0,
        exec_count:p.count,
        total_exec:p.total,
        max_exec:p.max,
        min_exec:p.min
      }
    }
  },
  'min_exec':{
    label:'最小执行时间',
    format:format.numSecond,
    parse:function(p){
      return {
        avg_exec:p.count?p.total/p.count:0,
        exec_count:p.count,
        total_exec:p.total,
        max_exec:p.max,
        min_exec:p.min
      }
    }
  },
  'total_receive_size':{
    order:'1',
    label:'传输数据量',
    format:dataSize,
    parse:function(p){
      return {
        total_receive_size:p.val
      }
    }
  },
  'crash_count':{
    order:'303',
    label:'崩溃次数',
    format:format.integer,
    parse:function(p){
      return {
        crash_count:p.count
      }
    }
  },
  'crash_rate':{
    order:'', // 崩溃率
    label:'崩溃率',
    format:format.rate,
    parse:function(p){
      return {
        crash_rate:p.appUseCount?p.count/p.appUseCount:0
      }
    }
  },
  'crash_rate_2':{
    order:'',//崩溃率无排序
    label:'崩溃率',
    format:format.rate,
    parse:function(p){
      return {
        crash_rate_2: p.crashRate
      }
    }
  },
  'http_similar_error_count':{
    order:'1',//崩溃率无排序
    label:'错误次数',
    format:format.integer,
    parse:function(p){
      return {
        http_similar_error_count:p.count
      }
    }
  },
  'activity_similar_trace_count':{
    order:'1',
    label:'发生次数',
    format:format.integer,
    parse:function(p){
      return {
        activity_similar_trace_count:p.count
      }
    }
  },
  'js_error_count':{
    order:'203',
    label:'JS Errors',
    format:format.integer,
    parse:function(p){
      return {
        js_error_count:p.count
      }
    }
  },
  'percentile_resp':{
    order:'1',
    label:'响应时间',
    format:format.numSecond,
    parse:function(p){
      return {
        percentile_resp:p.val
      }
    }
  },
  'socket_time':{
    order:'1',
    label:'耗时',
    format:format.numSecond,
    parse:function(p){
      return {
        socket_time:p.count?p.val/p.count:0
      }
    }
  },
  'framerate_listLine':{
    order:'1',
    label:'卡顿次数',
    format:format.integer,
    parse:function(p){
      return {
        framerate_listLine: p.count,
        framerate_listLine_extend_1: p.sm
      }
    }
  },
  'framerate_listLine_extend_1':{
    label:'最小流畅度',
    format:format.integer
  },
  'response_distribution':function (list, tmp) {
    var ratio = (tmp.ratio || 0) + list[0].percent;
    var index = tmp.index || 0;
    var item = list[0];

    var tip = item.rightBottom !== 'N'
      ? item.leftBottom+' ~ '+item.rightBottom+'ms：'+numeral(list[0].percent).format('0[.]00%')
      : item.leftBottom+'ms 以上：'+numeral(list[0].percent).format('0[.]00%');

    var result = {
      ratio:numeral(list[0].percent).format('0.00%'),
      tip:tip,
      value:Number(list[0].leftBottom)
    };

    tmp.index = index + 1;
    tmp.ratio = ratio;

    return result;
  },
  'performance_AVG_RESPONSETIME':{
    format:format.numSecond,
    label: '平均响应时间',
    parse:function (item) {
      return {
        performance_AVG_RESPONSETIME: item.val
      };
    }
  },
  'performance_TRANSFER_BYTE':{
    format:format.dataSize,
    label: '传输数据量',
    parse:function (item) {
      return {
        performance_TRANSFER_BYTE: item.val
      };
    }
  },
  'performance_NET_ERROR_RATE':{
    format:format.rate,
    label: '网络错误率',
    parse:function (item) {
      return {
        performance_NET_ERROR_RATE: item.val
      };
    }
  },
  'performance_DAILY_ACTIVE':{
    format:format.integer,
    label: '活跃用户',
    parse:function (item) {
      return {
        performance_DAILY_ACTIVE: item.val
      };
    }
  },
  'performance_CRASH_RATE':{
    format:format.rate,
    label: '崩溃率',
    parse:function (item) {
      return {
        performance_CRASH_RATE: item.val
      };
    }
  },
  'performance_CRASH':{
    format:format.integer,
    label: '崩溃次数',
    parse:function (item) {
      return {
        performance_CRASH: item.val
      };
    }
  },
  'chinaMap_AVG_RESPONSETIME': {
    label:'平均响应时间',
    format:format.numSecond
  },
  'chinaMap_TRANSFER_BYTE': {
    label:'传输数据量',
    format:format.dataSize
  },
  'chinaMap_NET_ERROR_RATE': {
    label:'网络错误率',
    format:format.rate
  }
  ,'avg_resp_ajax':{
    order:'202',
    label:'平均响应时间',
    format:format.numSecs,
    parse:function(p){
      return {
        avg_resp_ajax:p.count ? p.total / p.count : 0,
        count_resp_ajax:p.count,
        min_resp_ajax:p.min,
        max_resp_ajax:p.max
      };
    }
  }
  ,count_resp_ajax:{
    order:'203',
    label:'响应次数',
    format:function (value) {
      return format.integer(value) + ' 次';
    },
    parse:function (p) {
      return {
        avg_resp_ajax:p.count ? p.total / p.count : 0,
        count_resp_ajax:p.count,
        min_resp_ajax:p.min,
        max_resp_ajax:p.max
      };
    }
  }
  ,min_resp_ajax:{
    label:'响应时间最小值',
    format:format.numSecs
  }
  ,max_resp_ajax:{
    label:'响应时间最大值',
    format:format.numSecs
  }
}
module.exports.sortMap = _.mapObject(propConfig,function(v){
  return v.order;
})
var getPropValByViewKey = module.exports.getPropValByViewKey = function getPropValByViewKey(p,viewKey){
  var config = propConfig[viewKey];
  var pointData = config.parse(p)
  return {
    value:pointData[viewKey],
    fmtVal:config.format(pointData[viewKey]),
    label:config.label,
    pointData:pointData
  }
}
function parsePoint(p,viewKey){
  var point = getPropValByViewKey(p,viewKey)
  return {
    x:p.st,
    y:point.value,
    customData:_.chain(point.pointData)
    .omit(viewKey)
    .omit(function(v){
      return _.isNaN(v)||_.isUndefined(v)||_.isNull(v)
    })
    .mapObject(function(v,k){
      return {
        label:propConfig[k].label,
        fmtVal:propConfig[k].format(v)
      }
    })
    .extend({
      y:{
        label:point.label,
        fmtVal:point.fmtVal
      },
      startTime:p.st,
      endTime:p.et
    }).value()
  }
}
function serieNameOriginal(item){
  return _.escape(item.key?(item.key.alias?item.key.alias:item.key.name):item.name)
}
function serieNameClassifyFixed(item){
  return item.key.name === 'unfixed'?'未解决':'已解决'
}
function serieNameClassifyCrashName(item){
  return crashNameFormat(serieNameOriginal(item)).reason
}
function parseToChartSingle(target,params,options){
  var viewKey = params.viewKey
  var currentOptions = options || {};
  var r = {
    yAxis:{
      labels:{
        formatter:function(){
          var formattedValue = propConfig[viewKey].format(this.value);
          return currentOptions.formatter ? currentOptions.formatter.call(this, formattedValue, currentOptions) : formattedValue;
        }
      },
      useHTML: currentOptions.formatter ? true : false,
      maxPadding:0
    },
    series:_.chain([target]).map(function(item,n){
      var name;
      if(params.customClassify){
        name = serieNameClassifyFixed(item)
      }else if(params.classify==='crashname'){
        name = serieNameClassifyCrashName(item)
      }else{
        name = serieNameOriginal(item)
      }
      return {
        id:item.key?item.key.id:item.id,
        name:name,
        data:_.chain(item.data).sortBy('st').map(function(p){
          var point = getPropValByViewKey(p,viewKey)
          return {
            x:p.st,
            y:point.value,
            customData:_.chain(point.pointData)
                        .omit(viewKey)
                        .omit(function(v){
                          return _.isNaN(v)||_.isUndefined(v)||_.isNull(v)
                        })
                        .mapObject(function(v,k){
                          return {
                            label:propConfig[k].label,
                            fmtVal:propConfig[k].format(v)
                          }
                        })
                        .extend({
                          y:{
                            label:point.label,
                            fmtVal:point.fmtVal
                          },
                          startTime:p.st,
                          endTime:p.et
                        })
                        .value()
          }
        }).value()
      }
    }).value()
  }
  if(propConfig[viewKey].format===format.dataSize){
    r.yAxis.tickPositioner = function () {
      var intergate = function (value) {
        var index = 1;
        var currentValue = -1;
        do {
          currentValue = value / Math.pow(1024,index);
          index++;
        } while (currentValue > 1024);
        return Math.ceil(currentValue) * Math.pow(1024, index - 1);
      };

      var positions = []
        , increment = Math.ceil(intergate(this.dataMax) / (this.tickAmount - 1));

      for (var i = 0; i < this.tickAmount; i++) {
        positions.push(increment * i);
      }

      return positions;
    }
  }
  if(propConfig[viewKey].format===format.integer){
    r.yAxis.minTickInterval = 1;
    // r.yAxis.labels.formatter = undefined
  }
  return r
}

var supportedMap = _(china.features).map(function(a) {
  return a.properties['cn-code'];
})

function parseToChinaMap(target,params,options) {
  var config = propConfig[params.viewKey];

  return {
    mapData:china,
    joinBy:'cn-code',
    data:_.chain(target.result)
    .filter(function (item) {
      return _.contains(supportedMap,item.name);
    })
    .map(function(item) {
      var p = item.combData;
      return {
        value:p.val,
        fmtVal:config.format(p.val),
        name:item.name,
        label:config.label,
        startTime:p.st,
        endTime:p.et,
        'cn-code':item.name
      }
    }).value()
  };
}
module.exports.parseToChart2 = function (data,params,options) {
  if (params.__url && params.__type==='laterBlock') {
    var parser = propConfig[params.viewKey];
    var tmp = {};
    return _.chain(data.result)
            .sortBy(function(item){
              return parseInt(item.data[0].leftBottom);
            })
            .map(function(item) {
              return parser(item.data, tmp);
            })
            .value();
  } else if (params.__url &&
             params.__type==='double-common' &&
             params.viewKey.length===data.result.length &&
             params.viewKey.length===2) {
    var viewKeys = params.viewKey;

    params.viewKey = viewKeys[0];
    var left = parseToChartSingle(data.result[0], params, options);
    params.viewKey = viewKeys[1];
    var right = parseToChartSingle(data.result[1], params, options);
    right.yAxis.opposite = true;
    if (left.series[0].name === right.series[0].name) {
      right.series[0].name += ' ';
    }
    right.series[0].yAxis = 1;

    return {
      yAxis:[left.yAxis, right.yAxis],
      series:[left.series[0], right.series[0]]
    };
  } else if (params.__url && params.__type==='chinaMap') {
    return parseToChinaMap(data,params,options);
  } else if (params.__type==='common') {
    return exports.parseToChart(data,params,options);
  }
}
module.exports.parseToChart = function parseToChart(data,params,options){
  var viewKey = params.viewKey
  var r = {
    yAxis:{
      labels:{
        formatter:function(){
          return propConfig[viewKey].format(this.value)
        }
      },
      maxPadding:0
    },
    series:_.chain(data.classifybyfixed?data.classifybyfixed.result:data.result).map(function(item,n){
      var name;
      if(params.customClassify){
        name = serieNameClassifyFixed(item)
      }else if(params.classify==='crashname'){
        name = serieNameClassifyCrashName(item)
      }else{
        name = serieNameOriginal(item)
      }
      return {
        id:item.key?item.key.id:item.id,
        name:name,
        data:_.chain(item.data).map(function(p){
          return parsePoint(p,viewKey)
        }).value()
      }
    }).value()
  }
  if(propConfig[viewKey].format===format.dataSize){
    r.yAxis.tickInterval = 1;
  }
  if(propConfig[viewKey].format===format.integer){
    r.yAxis.minTickInterval = 1;
    r.yAxis.labels.formatter = undefined
  }
  return r
}
var coreApi = module.exports.coreApi = ApiFactory({
  url:function(params){
    return BlueWare.urlPrefix+'/app/'+params.appId+'/'+params.urlName+'.json'
  },
  optionParams:['appId','urlName','viewKey','customClassify'],
  params:{
    appId:{
      defaultValue:BlueWare.appId
    },
    urlName:{},
    order:{},
    spanTime:{},
    size:{
      defaultValue:30
    },
    classify:{},
    offset:{
      defaultValue:0
    },
    limit:{
      defaultValue:5
    },
    appVersionId:{
      defaultValue:BlueWare.appVersionId
    }
  }
})
var corePostApi = module.exports.corePostApi = ApiFactory({
  url:function(params){
    return BlueWare.urlPrefix+'/app/'+params.appId+'/'+params.urlName+'.json'
  },
  method: 'POST',
  optionParams:['appId','urlName','viewKey','customClassify'],
  params:{
    appId:{
      defaultValue:BlueWare.appId
    },
    urlName:{},
    order:{},
    spanTime:{},
    size:{
      defaultValue:30
    },
    classify:{},
    offset:{
      defaultValue:0
    },
    limit:{
      defaultValue:5
    },
    appVersionId:{
      defaultValue:BlueWare.appVersionId
    }
  }
})
var corePutApi = module.exports.corePutApi = ApiFactory({
  url:function(params){
    return BlueWare.urlPrefix+'/app/'+params.appId+'/'+params.urlName+'.json'
  },
  method: 'PUT',
  optionParams:['appId','urlName','viewKey','customClassify'],
  params:{
    appId:{
      defaultValue:BlueWare.appId
    },
    urlName:{},
    order:{},
    spanTime:{},
    size:{
      defaultValue:30
    },
    classify:{},
    offset:{
      defaultValue:0
    },
    limit:{
      defaultValue:5
    },
    appVersionId:{
      defaultValue:BlueWare.appVersionId
    }
  }
})
var coreDeleteApi = module.exports.coreDeleteApi = ApiFactory({
  url:function(params){
    return BlueWare.urlPrefix+'/app/'+params.appId+'/'+params.urlName+'.json'
  },
  method: 'DELETE',
  optionParams:['appId','urlName','viewKey','customClassify'],
  params:{
    appId:{
      defaultValue:BlueWare.appId
    },
    urlName:{},
    order:{},
    spanTime:{},
    size:{
      defaultValue:30
    },
    classify:{},
    offset:{
      defaultValue:0
    },
    limit:{
      defaultValue:5
    },
    appVersionId:{
      defaultValue:BlueWare.appVersionId
    }
  }
})
module.exports.parseToTopbar = function parseToTopbar(data,params,options){
  options = options||{};
  var viewKey = params.viewKey
    , classify = params.classify
    , classifyTree = options.classifyTree
    , routePrefix = options.parent?options.parent.routeUrl:''
  var parsed = _.chain(data.result).map(function(item){
    return _.extend(getPropValByViewKey(item.combData,viewKey),{
      id:item.key?item.key.id:item.id,
      name:item.key?item.key.name:item.name,
      tip:item.key?(item.key.alias?item.key.alias:item.key.name):item.name,
      startTime:item.combData.st,
      endTime:item.combData.et
    }, options.parser && options.parser.itemMapper ? options.parser.itemMapper(item) : null)
  }).value()
  var total = _.chain(parsed).pluck('value')
      .reduce(function(v1,v2){return v1+v2},0).value()
  return _.chain(parsed).map(function(item){
    var routeUrl = routePrefix+'/'+classify+'/'+item.id
    var result = _.extend({},item,{
      ratio:total?item.value/total:0,
      routeUrl:routeUrl,
      hasChildren:classifyTree&&classifyTree.length>1,
      fetchChildren:function(){
        if (classifyTree.length <= 1) {
          return null;
        }
        var parent = this
        var childParam = {
          classify:classifyTree[1].key
        }
        if(classifyTree[1].options){
          _.extend(childParam,_.omit(classifyTree[1].options, 'parser'))
        }
        childParam[classifyTree[1].requireId] = item.id
        return coreApi(params,childParam).fetch()
        .then(function(innerData,innerParams){
          parent.children = {
            data:parseToTopbar(innerData,innerParams,_.extend({}, classifyTree[1].options, {
              classifyTree:classifyTree.slice(1),
              parent:parent
            }))
          }
        },function(err){
          parent.children = {
            error:err
          }
        },function(innerParams){
          parent.children = {
            loading:true,
            params:innerParams
          }
        });
      }
    })
    return _.extend(result, options.parser && options.parser.parsedItemMapper
                              ? options.parser.parsedItemMapper(result)
                              : null)
  }).value()
}
module.exports.parseToTopbar2 = function parseToTopbar2(data,params,options){
  options = options||{};
  var viewKey = params.viewKey
    , classify = params.classify
    , classifyTree = options.classifyTree
    , routePrefix = options.parent?options.parent.routeUrl:''
  var parsed = _.chain(data.result).map(function(item){
    return _.extend(getPropValByViewKey(item.combData,viewKey),{
      id:item.key?item.key.id:item.id,
      name:item.key?item.key.name:item.name,
      tip:item.key?(item.key.alias?item.key.alias:item.key.name):item.name,
      startTime:item.combData.st,
      endTime:item.combData.et
    }, options.parser && options.parser.itemMapper ? options.parser.itemMapper(item) : null)
  }).value()
  var total = _.chain(parsed).pluck('value')
      .reduce(function(v1,v2){return v1+v2},0).value()
  return _.chain(parsed).map(function(item){
    var routeUrl = routePrefix+'/'+classify+'/'+encodeURIComponent(item.id)
    var result = _.extend({},item,{
      ratio:total?item.value/total:0,
      routeUrl:routeUrl,
      hasChildren:classifyTree&&classifyTree.length>1,
      fetchChildren:function(){
        if (classifyTree.length <= 1) {
          return null;
        }
        var parent = this
        var childParam = {
          classify:classifyTree[1].key
        }
        if(classifyTree[1].options){
          _.extend(childParam,_.omit(classifyTree[1].options, 'parser'))
        }
        childParam[classifyTree[1].requireId] = item.id
        return coreApi(params,childParam).fetch()
        .then(function(innerData,innerParams){
          parent.children = {
            data:parseToTopbar2(innerData,innerParams,_.extend({}, classifyTree[1].options, {
              classifyTree:classifyTree.slice(1),
              parent:parent
            }))
          }
        },function(err){
          parent.children = {
            error:err
          }
        },function(innerParams){
          parent.children = {
            loading:true,
            params:innerParams
          }
        });
      }
    })
    return _.extend(result, options.parser && options.parser.parsedItemMapper
                              ? options.parser.parsedItemMapper(result)
                              : null)
  }).value()
}
var restApi = module.exports.restApi = ApiFactory({
  url:function(params) {
    return BlueWare.pageUrlPrefix + '/' + params.__url;
  },
  optionParams:['__url','__type','viewKey'],
  params:{
    __url:{defaultValue:''},
    __type:{defaultValue:'common'},
    size:{defaultValue:1},
    offset:{defaultValue:0},
    limit:{defaultValue:1}
  }
});
var restPostApi = module.exports.restPostApi = ApiFactory({
  url:function(params) {
    return BlueWare.pageUrlPrefix + '/' + params.__url;
  },
  method:'post',
  optionParams:['__url','__type','viewKey'],
  params:{
    __url:{defaultValue:''},
    __type:{defaultValue:'common'},
    size:{defaultValue:1},
    offset:{defaultValue:0},
    limit:{defaultValue:1}
  }
});
var defaultApi = module.exports.defaultApi = ApiFactory({
  url: function(params) {
    return BlueWare.pageUrlPrefix + '/' + params.__url;
  },
  optionParams: ['__url'],
  params: {
    __url: {defaultValue: ''}
  }
});
var defaultPostApi = module.exports.defaultPostApi = ApiFactory({
  url: function(params) {
    return BlueWare.pageUrlPrefix + '/' + params.__url;
  },
  method: 'post',
  optionParams: ['__url'],
  params: {
    __url: {defaultValue: ''}
  }
});
var request2 = function () {
  var args = _.chain(arguments)
              .toArray()
              .reduce(function (left, right) {
                _.each(right, function (value, key) {
                  var leftValue = left[key];

                  if (_.isFunction(leftValue)) {
                    leftValue = leftValue.call(left);
                  }
                  if (_.isFunction(value)) {
                    value = value.call(right);
                  }

                  if (leftValue === null || leftValue === undefined || (value === null || value === undefined)) {
                    left[key] = value;
                  } else if (typeof leftValue !== typeof value) {
                    throw Error('type not same.');
                  } else if (_.isObject(leftValue)) {
                    _.extend(leftValue, value);
                  } else if (_.isBoolean(leftValue)) {
                    left[key] = leftValue && value;
                  } else {
                    left[key] = leftValue + value;
                  }
                });

                return left;
              }, {})
              .value();
  return request(args.url, args.method, args.body);
};
module.exports.request2 = request2.bind(null, {
  url: BlueWare.pageUrlPrefix + '/'
});
var request = module.exports.request = function (url, method, body) {
  method = (method || 'GET').toUpperCase();

  var options = {
    url: url,
    cache: false,
    type: method
  };

  if(body) {
    options.data = body;
    if(typeof body === 'object' && (method === 'POST' || method === 'PUT')) {
      options.data = JSON.stringify(options.data);
      options.contentType = 'application/json';
    }
  }

  var deferred = $.Deferred();
  deferred.notify();

  var $ajax = $.ajax(options);
  $ajax
    .fail(deferred.reject)
    .done(deferred.resolve)
    .always(function() {
      $ajax = null;
    });

  return deferred.promise();
};
var coreApi2 = module.exports.coreApi2 = ApiFactory({
  url:function(params){
    return 'https://static.oneapm.com/assets/mi'+BlueWare.urlPrefix+'/app/'+params.appId+'/'+params.urlName+'.json'
  },
  optionParams:['appId','urlName','viewKey','customClassify'],
  params:{
    appId:{
      defaultValue:BlueWare.appId
    },
    urlName:{},
    order:{},
    spanTime:{},
    size:{
      defaultValue:30
    },
    classify:{},
    offset:{
      defaultValue:0
    },
    limit:{
      defaultValue:5
    },
    appVersionId:{
      defaultValue:BlueWare.appVersionId
    }
  }
})
var combAnalysisApi = module.exports.combAnalysisApi = ApiFactory({
  url:function(params){
    return BlueWare.urlPrefix+'/app/'+params.appId+'/combAnalysis/'+params.urlName+'.json'
  },
  method:'post',
  optionParams:['appId','urlName','viewKey','isCombAnalysis','category'],
  params:{
    isCombAnalysis:{
      defaultValue:true
    },
    appId:{
      defaultValue:BlueWare.appId
    },
    appVersionId:{
      defaultValue:''
    },
    osId:{
      defaultValue:''
    },
    osVersionId:{
      defaultValue:''
    },
    crashNameId:{
      defaultValue:''
    },
    exceptionType:{
      defaultValue:''
    },

    imsi:{
      defaultValue:''
    },
    deviceTypeId:{
      defaultValue:''
    },
    manufacturerId:{
      defaultValue:''
    },
    modelId:{
      defaultValue:''
    },

    countryCodeId:{
      defaultValue:''
    },
    regionCodeId:{
      defaultValue:''
    },
    carriesId:{
      defaultValue:''
    },
    netTypeId:{
      defaultValue:''
    },
    domainId:{
      defaultValue:''
    },
    urlId:{
      defaultValue:''
    },
    statusCode:{
      defaultValue:''
    },
    errorCode:{
      defaultValue:''
    },

    urlName:{},
    order:{},
    spanTime:{},
    size:{
      defaultValue:30
    },
    classify:{},
    offset:{
      defaultValue:0
    },
    limit:{
      defaultValue:5
    }
  }
})
var combAnalysisDetailApi = module.exports.combAnalysisDetailApi = ApiFactory({
  url:function(params){
    var urlName;
    switch (params.category) {
      case 'crash':
        urlName = BlueWare.platform.toLowerCase()+'_crash_detail_list'
        break;
      case 'httperror':
        urlName = 'httptrace_detail_list'
        break;
      case 'networkerror':
        urlName = 'httptrace_detail_list'
        break;
      case 'httptransaction':
        urlName = 'httptrace_detail_list'
        break;
      default:

    }
    return BlueWare.urlPrefix+'/app/'+params.appId+'/combAnalysis/'+params.urlName+'.json'
  },
  method:'post',
  optionParams:['appId','isCombAnalysis','category','viewKey'],
  params:{
    isCombAnalysis:{
      defaultValue:true
    },
    appId:{
      defaultValue:BlueWare.appId
    },
    appVersionId:{
      defaultValue:''
    },
    osId:{
      defaultValue:''
    },
    osVersionId:{
      defaultValue:''
    },
    crashNameId:{
      defaultValue:''
    },
    exceptionType:{
      defaultValue:''
    },
    imsi:{
      defaultValue:''
    },
    deviceTypeId:{
      defaultValue:''
    },
    manufacturerId:{
      defaultValue:''
    },
    modelId:{
      defaultValue:''
    },

    countryCodeId:{
      defaultValue:''
    },
    regionCodeId:{
      defaultValue:''
    },
    carriesId:{
      defaultValue:''
    },
    netTypeId:{
      defaultValue:''
    },
    domainId:{
      defaultValue:''
    },
    urlId:{
      defaultValue:''
    },
    statusCode:{
      defaultValue:''
    },
    errorCode:{
      defaultValue:''
    },

    order:{},
    spanTime:{},
    size:{
      defaultValue:30
    },
    classify:{},
    offset:{
      defaultValue:0
    },
    limit:{
      defaultValue:5
    }
  }
})
